Allow user to delete the scenarios agents with it

Dominik Sander vor 8 Jahren
Ursprung
Commit
98fae41421

+ 1 - 1
app/controllers/scenarios_controller.rb

@@ -97,7 +97,7 @@ class ScenariosController < ApplicationController
97 97
 
98 98
   def destroy
99 99
     @scenario = current_user.scenarios.find(params[:id])
100
-    @scenario.destroy
100
+    @scenario.destroy_with_mode(params[:mode])
101 101
 
102 102
     respond_to do |format|
103 103
       format.html { redirect_to scenarios_path }

+ 19 - 1
app/models/scenario.rb

@@ -16,7 +16,25 @@ class Scenario < ActiveRecord::Base
16 16
 
17 17
   validate :agents_are_owned
18 18
 
19
-  protected
19
+  def destroy_with_mode(mode)
20
+    case mode
21
+    when 'all_agents'
22
+      Agent.destroy(agents.pluck(:id))
23
+    when 'unique_agents'
24
+      Agent.destroy(unique_agent_ids)
25
+    end
26
+
27
+    destroy
28
+  end
29
+
30
+  private
31
+
32
+  def unique_agent_ids
33
+    agents.joins(:scenario_memberships)
34
+          .group('scenario_memberships.agent_id')
35
+          .having('count(scenario_memberships.agent_id) = 1')
36
+          .pluck('scenario_memberships.agent_id')
37
+  end
20 38
 
21 39
   def agents_are_owned
22 40
     errors.add(:agents, "must be owned by you") unless agents.all? {|s| s.user == user }

+ 46 - 0
app/views/scenarios/_confirm_deletion_modal.html.erb

@@ -0,0 +1,46 @@
1
+<div id="confirm-scenario-deletion-<%= scenario.id %>" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
2
+  <div class="modal-dialog">
3
+    <div class="modal-content">
4
+      <%= form_for(scenario, url: scenario_path(scenario), method: :delete) do |f| %>
5
+        <div class="modal-header">
6
+          <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
7
+          <h4 class="modal-title">
8
+            <% if @scenario && @scenario == scenario %>
9
+              How do you want to delete this Scenario?
10
+            <% else %>
11
+              How do you want to delete the Scenario '<%= scenario.name %>'?
12
+            <% end %>
13
+          </h4>
14
+        </div>
15
+        <div class="modal-body">
16
+          <div class="radio">
17
+            <%= label_tag do %>
18
+              <%= radio_button_tag :mode, '', true %>
19
+              <h4><span class="label label-success">Scenario only</span></h4>
20
+              Only delete the Scenerio, keep the Agents.
21
+            <% end %>
22
+          </div>
23
+          <div class="radio">
24
+            <%= label_tag do %>
25
+              <%= radio_button_tag :mode, :unique_agents %>
26
+              <h4><span class="label label-warning">Scenario and unique Agents</span></h4>
27
+              Also deletes Agents that are used in this Scenario only.
28
+            <% end %>
29
+          </div>
30
+          <div class="radio">
31
+            <%= label_tag do %>
32
+              <%= radio_button_tag :mode, :all_agents %>
33
+              <h4><span class="label label-danger">Scenario and all included Agents</span></h4>
34
+              Deletes Scenario and all included Agents, even if they are used in different Scenarios.
35
+            <% end %>
36
+          </div>
37
+        </div>
38
+        <div class="modal-footer">
39
+          <%= f.button 'Abort', class: 'btn btn-default', 'data-dismiss' => 'modal' %>
40
+          <%= f.submit 'Delete', class: 'btn btn-danger' %>
41
+        </div>
42
+      <% end %>
43
+    </div>
44
+  </div>
45
+</div>
46
+

+ 2 - 1
app/views/scenarios/index.html.erb

@@ -31,8 +31,9 @@
31 31
                 <%= link_to 'Show', scenario, class: "btn btn-default" %>
32 32
                 <%= link_to 'Edit', edit_scenario_path(scenario), class: "btn btn-default" %>
33 33
                 <%= link_to 'Share', share_scenario_path(scenario), class: "btn btn-default" %>
34
-                <%= link_to 'Delete', scenario_path(scenario), method: :delete, data: { confirm: "This will remove the '#{scenario.name}' Scenerio from all Agents and delete it.  Are you sure?" }, class: "btn btn-default" %>
34
+                <%= link_to 'Delete', '#', data: { toggle: 'modal', target: "#confirm-scenario-deletion-#{scenario.id}"}, class: "btn btn-default" %>
35 35
               </div>
36
+              <%= render 'scenarios/confirm_deletion_modal', scenario: scenario %>
36 37
             </td>
37 38
           </tr>
38 39
         <% end %>

+ 2 - 1
app/views/scenarios/show.html.erb

@@ -23,8 +23,9 @@
23 23
           <%= link_to icon_tag('glyphicon-refresh') + ' Update', new_scenario_imports_path(url: @scenario.source_url), class: "btn btn-default" %>
24 24
         <% end %>
25 25
         <%= link_to icon_tag('glyphicon-share-alt') + ' Share', share_scenario_path(@scenario), class: "btn btn-default" %>
26
-        <%= link_to icon_tag('glyphicon-trash') + ' Delete', scenario_path(@scenario), method: :delete, data: { confirm: "This will remove the '#{@scenario.name}' Scenerio from all Agents and delete it.  Are you sure?" }, class: "btn btn-default" %>
26
+        <%= link_to icon_tag('glyphicon-trash') + ' Delete', '#', data: { toggle: 'modal', target: "#confirm-scenario-deletion-#{@scenario.id}"}, class: "btn btn-default" %>
27 27
       </div>
28 28
     </div>
29 29
   </div>
30 30
 </div>
31
+<%= render 'scenarios/confirm_deletion_modal', scenario: @scenario %>

+ 6 - 0
spec/controllers/scenarios_controller_spec.rb

@@ -150,5 +150,11 @@ describe ScenariosController do
150 150
         delete :destroy, :id => scenarios(:jane_weather).to_param
151 151
       }.to raise_error(ActiveRecord::RecordNotFound)
152 152
     end
153
+
154
+    it "passes the mode to the model" do
155
+      expect {
156
+        delete :destroy, id: scenarios(:bob_weather).to_param, mode: 'all_agents'
157
+      }.to change(Agent, :count).by(-2)
158
+    end
153 159
   end
154 160
 end

+ 4 - 0
spec/fixtures/scenario_memberships.yml

@@ -6,6 +6,10 @@ jane_rain_notifier_agent_scenario_membership:
6 6
   agent: jane_rain_notifier_agent
7 7
   scenario: jane_weather
8 8
 
9
+jane_rain_notifier_agent_scenario_membership_duplicate:
10
+  agent: jane_weather_agent
11
+  scenario: jane_weather_duplicate
12
+
9 13
 bob_weather_agent_scenario_membership:
10 14
   agent: bob_weather_agent
11 15
   scenario: bob_weather

+ 6 - 0
spec/fixtures/scenarios.yml

@@ -5,6 +5,12 @@ jane_weather:
5 5
   public: false
6 6
   guid: random-guid-generated-by-bob
7 7
 
8
+jane_weather_duplicate:
9
+  name: Jane's duplicated, incomplete weather alert Scenario
10
+  user: jane
11
+  public: false
12
+  guid: random-guid-generated-by-jane2
13
+
8 14
 bob_weather:
9 15
   name: Bob's weather alert Scenario
10 16
   user: bob

+ 31 - 0
spec/models/scenario_spec.rb

@@ -64,4 +64,35 @@ describe Scenario do
64 64
       }.to change { users(:bob).reload.scenario_count }.by(-1)
65 65
     end
66 66
   end
67
+
68
+  context '#unique_agents' do
69
+    it "equals agents when no agents are shared" do
70
+      agent_ids        = scenarios(:bob_weather).agents.map(&:id).sort
71
+      unique_agent_ids = scenarios(:bob_weather).send(:unique_agent_ids).sort
72
+      expect(agent_ids).to eq(unique_agent_ids)
73
+    end
74
+
75
+    it "includes only agents that are not present in two scnearios" do
76
+      unique_agent_ids = scenarios(:jane_weather).send(:unique_agent_ids)
77
+      expect(unique_agent_ids).to eq([agents(:jane_rain_notifier_agent).id])
78
+    end
79
+
80
+    it "returns no agents when all are also used in a different scenario" do
81
+      expect(scenarios(:jane_weather_duplicate).send(:unique_agent_ids)).to eq([])
82
+    end
83
+  end
84
+
85
+  context '#destroy_with_mode' do
86
+    it "only destroys the scenario when no mode is passed" do
87
+      expect { scenarios(:jane_weather).destroy_with_mode('') }.not_to change(Agent, :count)
88
+    end
89
+
90
+    it "only destroys unique agents when 'unique_agents' is passed" do
91
+      expect { scenarios(:jane_weather).destroy_with_mode('unique_agents') }.to change(Agent, :count).by(-1)
92
+    end
93
+
94
+    it "destroys all agents when 'all_agents' is passed" do
95
+      expect { scenarios(:jane_weather).destroy_with_mode('all_agents') }.to change(Agent, :count).by(-2)
96
+    end
97
+  end
67 98
 end